/*================================================================
*   File Name：net.c
*   Mail: a1277992967@163.com 
*   blog: http://www.ycst.club/suggest/ 
*   Author：ycst
*   Created Time：2022年08月15日 星期一 11时03分16秒
*   Describe：
*
================================================================*/

#include "../include/net.h"
#include "../include/server.h"
#include "../include/fd_list.h"
#include "../include/device_hash.h"
#include "../include/db.h"


int cfd_list[100] = {0};
/*
 *	@describe：	初始化网络监听描述符，并返回。
 *	@parmet:	NULL
 *	@return		监听描述符
 */
int InitNet(){
    int sLen = sizeof(sock_server);
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    sock_server.sin_family = AF_INET;
    sock_server.sin_port = htons(9000);
    sock_server.sin_addr.s_addr = INADDR_ANY;
	int on = 1;
	setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	bind(sfd,(struct sockaddr*)&sock_server,sLen);
    listen(sfd,10);
	return sfd;
}


/*
 *	@describe：	接收客户端，并进入主循环。
 *	@parmet:
 *	@iServer:	监听描述符
 *	@return		void
 */
void AcceptClient(int iServer){

	#if 1
	int sfd = iServer;
	int cfd = 0;
	int sLen = sizeof(sock_server);
    int cLen = sizeof(sock_client);
	int maxid = 0;
	//int cfd_list[100] = {0};
	int cfd_len = sizeof(cfd_list) / sizeof(int);
	char send_buf[100]="";
    char recv_buf[100]="";
    int i = 0;
    int count = 0;
    int m = 0;
    int res = 0;
    int flag = 0;
    

    List *list = CreateList();
    Hash *hash = CreateHash();

	//for(i = 0; i < 99; i++)	cfd_list[i] = -1;
	fd_set readfd;
	
	printf("net1 g_conn = %p\r\n", g_conn);
	for(i = 0; i < cfd_len; i++){
		cfd_list[i] = -1;
	}
	
	printf("net2 g_conn = %p\r\n", g_conn);
	
	FD_ZERO(&readfd);
	maxid = 0;
	
	struct timeval tim;
	tim.tv_sec = 0;
	tim.tv_usec = 0;

	
    while(1){
    		//printf("hello\r\n");
			FD_SET(sfd, &readfd);
			maxid = maxid > sfd ? maxid : sfd;
			for(i = 0; i < cfd_len; i++){
				if(cfd_list[i]  != -1){
					FD_SET(i, &readfd);
				}
			}
			flag = 1;
			res = select(maxid + 1, &readfd, NULL, NULL, &tim);
			//perror("error");
			//printf("res = %d\r\n",res);
			
#if 1
			if(res > 0){
				if(FD_ISSET(sfd, &readfd)){
					printf("新客户端链接成功\r\n");
					cfd = AcceptFd(sfd, &readfd);
					cfd_list[cfd] = 1;
					maxid = maxid > cfd ? maxid : cfd;
					
					dev_fd dev1;		//用来打包去insert到顺序表中
					dev1.fd = cfd;
					dev1.lTime = time(NULL);
					printf("cfd = %d\r\n", dev1.fd);
					int p = InsertList(list, dev1, -1);
					if(p == 0)	printf("成功\r\n");
					else	printf("失败\r\n");
				}
				else{
					for(i = 3; i <= maxid; i++){
						if(FD_ISSET(i, &readfd)){
							bzero(recv_buf, sizeof(recv_buf));
							res = recv(i, recv_buf, sizeof(recv_buf), 0);
							if(res <= 0){
								printf("断开链接\r\n");
								cfd_list[i] = -1;
								DeleteList(list, NULL, 0);
								maxid = DelFdFromSet(i, maxid, &readfd);
								printf("maxid = %d\r\n", maxid);
							}
							else{
								printf("客户端 %d 发来消息 ： \r\n", i);
								if(recv_buf[0] == 'C' && recv_buf[1] == 'M' && recv_buf[2] == 'D'){	
									printf("是CMD\r\n");								
									char cmd_id_buf[20] = {0};
									char cmd_type_buf[20] = {0};
									char cmd_major_buf[20] = {0};
									char cmd_min_buf[20] = {0};
									char cmd_result_buf[20] = {0};
									

									cmd_get_value(recv_buf, cmd_id_buf, cmd_get_device_id);
									cmd_get_value(recv_buf, cmd_type_buf, cmd_get_device_type);
									cmd_get_value(recv_buf, cmd_major_buf, cmd_get_major);
									cmd_get_value(recv_buf, cmd_min_buf, cmd_get_min);
									cmd_get_value(recv_buf, cmd_result_buf, cmd_get_result);
									
									char *argv[] = {cmd_id_buf, cmd_type_buf, cmd_major_buf, cmd_min_buf, cmd_result_buf};
									DHT11SaveCmdResult(6, argv);
									continue;
								}
								
								
								char id_buf[20] = {0};
								char type_buf[20] = {0};
								char hum_buf[20] = {0};
								char temp_buf[20] = {0};
								
								get_device_id(recv_buf, id_buf);
								get_device_type(recv_buf, type_buf);
								get_humidity(recv_buf, hum_buf);
								get_temperature(recv_buf, temp_buf);
								
								char *argv[] = {id_buf, type_buf, hum_buf, temp_buf};
								//DHT11SaveData(4, argv);
								//DHT11SaveDeviceInfo(4, argv);
								
								
								
								
								printf("device_id = %s\r\n", id_buf);
								printf("device_type = %s\r\n", type_buf);
								printf("humidity = %s\r\n", hum_buf);
								printf("temperature = %s\r\n", temp_buf);
								//strcpy(send_buf, "hello this is server");
                          		//send(i,send_buf,strlen(send_buf),0);
                          		
                          		dev_fd dev2;		//用来打包去search
								dev2.fd = i;
								dev2.lTime = time(NULL);
                          		int j = SearchItem(list, dev2);
                          		if(j < 0){
                          			printf("我数据库呢？？？\r\n");
                          			DHT11SaveData(4, argv);
									DHT11updateDeviceInfo(4, argv);
                          			int old_FD = 0;
                          			printf("i = %d 该文件描述符不在顺序表中，可能存于hash\r\n", i);
                          			data_t data1;	//用于去search
                          			data1.iFd = i;
                          			data1.lTime = time(NULL);
                          			strcpy(data1.strDeviceID, id_buf);
                          			int fd_res = FindDevice(hash, data1, &old_FD);
                          			if(fd_res == SYS_OK){
                          				fd_res = UpdateItem(hash, data1);
                          				printf("更新成功\r\n");
                          				
                          			}
                          			if(fd_res == SYS_ERROR){
                          				printf("更新失败\r\n");
                          				FD_CLR(i, &readfd);
                          				cfd_list[i] = -1;
                          				printf("超时断开\r\n");
                          			}
                          			
                          			if(fd_res == SYS_DEVICE_REINSERT){
                          				printf("可能存在断连情况,准备重新插入\r\n");
                          				FD_CLR(old_FD, &readfd);
                          				int dl = DeleteItem(hash, data1);
                          				printf("dl = %d\r\n", dl);
                          				InsertItem(hash, data1);
                          			}
                          			printf("-----------------\r\n");
                          			ShowHash(hash);
                          			printf("-----------------\r\n");
                          		}
                          		else{
                          			printf("i = %d该文件描述符在顺序表中\r\n", i);
                          			
                          			
                          			int difftime = time(NULL) - list->data[j].lTime;
                          			printf("difftime = %d\r\n", difftime);
                          			
                          			if(difftime > WAITIME){
                          				printf("------等待超时--------\r\n");
                          				FD_CLR(i, &readfd);
                          				cfd_list[i] = -1;
                          				DeleteList(list, NULL, j);
                          				continue;
                          			}
                          			
                          			DHT11SaveData(4, argv);
									DHT11SaveDeviceInfo(4, argv);
                          			DeleteList(list, NULL, j);
                          			
                          			data_t data1;		//用于生成到hash表中
                          			data1.iFd = i;
                          			data1.lTime = time(NULL);
                          			strcpy(data1.strDeviceID, id_buf);
                          			InsertItem(hash, data1);
                          			printf("-----------------\r\n");
                          			ShowHash(hash);
                          			printf("-----------------\r\n");
                          		}
							}
						}

					}	
						
				}
			}	
			
#endif
		else{
			for(int l = 0; l < 20; l++){
				if(time(NULL) - list->data[l].lTime > WAITIME && list->data[l].fd > 2){
					if(flag == 1){
						FD_CLR(list->data[l].fd, &readfd);
						close(list->data[l].fd);
						cfd_list[list->data[l].fd] = -1;
						DeleteList(list, NULL, l);
						flag = 0;
					}
				}
			}
		}
	
	}
#endif
}


/*
 *	@describe：	接收客户端并返回客户端描述符，添加到fd_set结构体中。
 *	@parmet:
 *	@iServer:	监听描述符
 *	@*pSet:		监听的源描述符集合
 *	@return		通信描述符
 */
int AcceptFd(int iServer, fd_set *pSet){
	if(pSet == NULL)	return -1;
	int cLen = sizeof(sock_server);
	int cfd = accept(iServer, (struct sockaddr *)&sock_client, &cLen);
	FD_SET(cfd, pSet);
	return cfd;
}


/*
 *	@describe：	从fd_set中删除通信描述符
 *	@parmet:
 *	@i:			通讯描述符
 *	@iMax:		最大描述符值
 *	@*pSet:		监听的源描述符集合
 *	@return		Select最大描述符值
 */
int DelFdFromSet(int i, int iMax, fd_set *pSet){
	if(pSet == NULL)	return -1;
	int max = 0;
	FD_CLR(i, pSet);
	if(i == iMax){
		for(int j = 0; j++; j < sizeof(cfd_list)){
			max = max > cfd_list[j] ? max :  cfd_list[j];
		}
		return max;
	}	
	//return iMax - 1;
	return iMax;
}









